/*******************************************************************************
 * Copyright (c) 2004, 2015 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     EclipseSource - adaptation for RAP
 *******************************************************************************/
package org.eclipse.ui.forms.widgets;

import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA;
import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.forms.internal.widgets.IHyperlinkAdapter;
import org.eclipse.ui.forms.internal.widgets.hyperlinkkit.HyperlinkLCA;
import org.eclipse.ui.internal.forms.widgets.FormUtil;
//import org.eclipse.swt.accessibility.*;
//import org.eclipse.ui.forms.FormColors;

/**
 * Hyperlink is a concrete implementation of the abstract base class that draws
 * text in the client area. Text can be wrapped and underlined. Hyperlink is
 * typically added to the hyperlink group so that certain properties are managed
 * for all the hyperlinks that belong to it.
 * <p>
 * Hyperlink can be extended.
 * <p>
 * <dl>
 * <dt><b>Styles:</b></dt>
 * <dd>SWT.WRAP</dd>
 * </dl>
 *
 * @see org.eclipse.ui.forms.HyperlinkGroup
 */
public class Hyperlink extends AbstractHyperlink {
  private String text;
// RAP [rh] Unused code: was used by paint code
//  private static final String ELLIPSIS = "..."; //$NON-NLS-1$
  private boolean underlined;
  // The tooltip is used for two purposes - the application can set
  // a tooltip or the tooltip can be used to display the full text when the
  // the text has been truncated due to the label being too short.
  // The appToolTip stores the tooltip set by the application.  Control.tooltiptext
  // contains whatever tooltip is currently being displayed.
  private String appToolTipText;

  // RAP [rh] Adapter to reach into widget implementation from within LCA
  private transient IHyperlinkAdapter hyperlinkAdapter;

  /**
   * Creates a new hyperlink control in the provided parent.
   *
   * @param parent
   *            the control parent
   * @param style
   *            the widget style
   */
  public Hyperlink(Composite parent, int style) {
    super(parent, style);
    initAccessible();
    text = ""; //$NON-NLS-1$
  }

  @Override
  @SuppressWarnings("unchecked")
  public <T> T getAdapter( final Class<T> adapter ) {
    if( adapter == IHyperlinkAdapter.class ) {
      if( hyperlinkAdapter == null ) {
        hyperlinkAdapter = new IHyperlinkAdapter() {
          private Color activeForeground;
          private Color activeBackground;
          private int underlineMode;
          @Override
          public void setActiveForeground( final Color activeForeground ) {
            this.activeForeground = activeForeground;
          }
          @Override
          public Color getActiveForeground() {
            return activeForeground;
          }
          @Override
          public void setActiveBackground( final Color activeBackground ) {
            this.activeBackground = activeBackground;
          }
          @Override
          public Color getActiveBackground() {
            return activeBackground;
          }
          @Override
          public void setUnderlineMode( final int underlineMode ) {
            this.underlineMode = underlineMode;
          }
          @Override
          public int getUnderlineMode() {
            return underlineMode;
          }
        };
      }
      return ( T )hyperlinkAdapter;
    } else if( adapter == WidgetLCA.class ) {
      return ( T )HyperlinkLCA.INSTANCE;
    }
    return super.getAdapter( adapter );
  }

  protected void initAccessible() {
    Accessible accessible = getAccessible();
    accessible.addAccessibleListener(new AccessibleAdapter() {
      @Override
      public void getName(AccessibleEvent e) {
        e.result = getText();
        if (e.result == null)
          getHelp(e);
      }

      @Override
      public void getHelp(AccessibleEvent e) {
        e.result = getToolTipText();
      }
    });
    accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
      @Override
      public void getChildAtPoint(AccessibleControlEvent e) {
        Point pt = toControl(new Point(e.x, e.y));
        e.childID = (getBounds().contains(pt)) ? ACC.CHILDID_SELF
            : ACC.CHILDID_NONE;
      }

      @Override
      public void getLocation(AccessibleControlEvent e) {
        Rectangle location = getBounds();
        Point pt = toDisplay(new Point(location.x, location.y));
        e.x = pt.x;
        e.y = pt.y;
        e.width = location.width;
        e.height = location.height;
      }

      @Override
      public void getChildCount(AccessibleControlEvent e) {
        e.detail = 0;
      }

      @Override
      public void getRole(AccessibleControlEvent e) {
        e.detail = ACC.ROLE_LINK;
      }

      @Override
      public void getDefaultAction (AccessibleControlEvent e) {
        e.result = SWT.getMessage ("SWT_Press"); //$NON-NLS-1$
      }

      @Override
      public void getState(AccessibleControlEvent e) {
        int state = ACC.STATE_NORMAL;
        if (Hyperlink.this.getSelection())
          state = ACC.STATE_SELECTED | ACC.STATE_FOCUSED;
        e.detail = state;
      }
    });

  }

  /**
   * Sets the underlined state. It is not necessary to call this method when
   * in a hyperlink group.
   *
   * @param underlined
   *            if <samp>true </samp>, a line will be drawn below the text for
   *            each wrapped line.
   */
  public void setUnderlined(boolean underlined) {
    this.underlined = underlined;
    redraw();
  }

  /**
   * Returns the underline state of the hyperlink.
   *
   * @return <samp>true </samp> if text is underlined, <samp>false </samp>
   *         otherwise.
   */
  public boolean isUnderlined() {
    return underlined;
  }

  /**
   * Overrides the parent by incorporating the margin.
   */
  @Override
  public Point computeSize(int wHint, int hHint, boolean changed) {
    checkWidget();
    int innerWidth = wHint;
    if (innerWidth != SWT.DEFAULT)
      innerWidth -= marginWidth * 2;
    Point textSize = computeTextSize(innerWidth, hHint);
    int textWidth = textSize.x + 2 * marginWidth;
    int textHeight = textSize.y + 2 * marginHeight;
    return new Point(textWidth, textHeight);
  }

  /**
   * Returns the current hyperlink text.
   *
   * @return hyperlink text
   */
  @Override
  public String getText() {
    return text;
  }

  /* (non-Javadoc)
   * @see org.eclipse.swt.widgets.Control#getToolTipText()
   */
  @Override
  public String getToolTipText () {
    checkWidget();
    return appToolTipText;
  }

  /* (non-Javadoc)
   * @see org.eclipse.swt.widgets.Control#setToolTipText(java.lang.String)
   */
  @Override
  public void setToolTipText (String string) {
    super.setToolTipText (string);
    appToolTipText = super.getToolTipText();
  }

  /**
   * Sets the text of this hyperlink.
   *
   * @param text
   *            the hyperlink text
   */
  public void setText(String text) {
    if (text != null)
      this.text = text;
    else
      this.text = ""; //$NON-NLS-1$
    redraw();
  }

// RAP [rh] Disabled because of disabled AbstractHyperlink#paintHyperlink()
//  /**
//   * Paints the hyperlink text.
//   *
//   * @param gc
//   *            graphic context
//   */
//  protected void paintHyperlink(GC gc) {
//    Rectangle carea = getClientArea();
//    Rectangle bounds = new Rectangle(marginWidth, marginHeight, carea.width
//        - marginWidth - marginWidth, carea.height - marginHeight
//        - marginHeight);
//    paintText(gc, bounds);
//  }
//
//  /**
//   * Paints the hyperlink text in provided bounding rectangle.
//   *
//   * @param gc
//   *            graphic context
//   * @param bounds
//   *            the bounding rectangle in which to paint the text
//   */
//  protected void paintText(GC gc, Rectangle bounds) {
//    gc.setFont(getFont());
//    gc.setForeground(getForeground());
//    if ((getStyle() & SWT.WRAP) != 0) {
//      FormUtil.paintWrapText(gc, text, bounds, underlined);
//    } else {
//      Point totalSize = computeTextSize(SWT.DEFAULT, SWT.DEFAULT);
//      boolean shortenText =false;
//      if (bounds.width<totalSize.x) {
//        // shorten
//        shortenText=true;
//      }
//      int textWidth = Math.min(bounds.width, totalSize.x);
//      int textHeight = totalSize.y;
//      String textToDraw = getText();
//      if (shortenText) {
//        textToDraw = shortenText(gc, getText(), bounds.width);
//        if (appToolTipText == null) {
//          super.setToolTipText(getText());
//        }
//      }
//      else {
//        super.setToolTipText(appToolTipText);
//      }
//      gc.drawText(textToDraw, bounds.x, bounds.y, true);
//      if (underlined) {
//        int descent = gc.getFontMetrics().getDescent();
//        int lineY = bounds.y + textHeight - descent + 1;
//        gc.drawLine(bounds.x, lineY, bounds.x + textWidth, lineY);
//      }
//    }
//  }
//
//  protected String shortenText(GC gc, String t, int width) {
//    if (t == null) return null;
//    int w = gc.textExtent(ELLIPSIS).x;
//    if (width<=w) return t;
//    int l = t.length();
//    int max = l/2;
//    int min = 0;
//    int mid = (max+min)/2 - 1;
//    if (mid <= 0) return t;
//    while (min < mid && mid < max) {
//      String s1 = t.substring(0, mid);
//      String s2 = t.substring(l-mid, l);
//      int l1 = gc.textExtent(s1).x;
//      int l2 = gc.textExtent(s2).x;
//      if (l1+w+l2 > width) {
//        max = mid;
//        mid = (max+min)/2;
//      } else if (l1+w+l2 < width) {
//        min = mid;
//        mid = (max+min)/2;
//      } else {
//        min = max;
//      }
//    }
//    if (mid == 0) return t;
//     return t.substring(0, mid)+ELLIPSIS+t.substring(l-mid, l);
//  }

  protected Point computeTextSize(int wHint, int hHint) {
    Point extent;
    GC gc = new GC(this);
    gc.setFont(getFont());
    if ((getStyle() & SWT.WRAP) != 0 && wHint != SWT.DEFAULT) {
      extent = FormUtil.computeWrapSize(gc, getText(), wHint);
    } else {
      extent = gc.textExtent(getText());
      if ((getStyle() & SWT.WRAP)==0 && wHint!=SWT.DEFAULT)
        extent.x = wHint;
    }
    gc.dispose();
    return extent;
  }

}
